package jwt

import (
	"encoding/json"
	"errors"
	"myserver/app/model"
	"myserver/app/model/auth"
	"myserver/app/redis"
	"myserver/app/types"
	"myserver/pkg/app"
	"myserver/pkg/constant"
	"myserver/pkg/global"
	"net/http"
	"strconv"
	"strings"
	"time"

	"github.com/gin-gonic/gin"
	"github.com/go-pay/gopay/pkg/jwt"
)

var jwtSecret []byte

type JwtUser struct {
	NickName string           `json:"nickName"`
	Account  string           `json:"account"`
	Phone    string           `json:"phone"`
	Sex      string           `json:"sex"`
	Uuid     string           `json:"uuid"`
	Id       int              `json:"-"`
	Shops    []types.UserShop `json:"shops"`
	Auth     int              `json:"auth"`
}
type userStdClaims struct {
	JwtUser
	//*models.User
	jwt.StandardClaims
}

func Setup() {
	jwtSecret = []byte(global.CONFIG.App.JwtSecret)
}
func GetToken(user types.User, d time.Duration) (string, error) {
	var (
		tokenString string
		u           JwtUser
	)
	expireTime := time.Now().Add(d)
	c, err := BackJwtUser(user)
	u = c
	if err != nil {
		return tokenString, err
	}
	stdClaims := jwt.StandardClaims{
		ExpiresAt: expireTime.Unix(),
		Id:        strconv.FormatInt(int64(u.Id), 10),
		Issuer:    "dcGo",
	}
	uClaims := userStdClaims{
		StandardClaims: stdClaims,
		JwtUser:        u,
	}
	token := jwt.NewWithClaims(jwt.SigningMethodHS256, uClaims)
	tokenString, err = token.SignedString(jwtSecret)
	if err != nil {
		return tokenString, err
	}
	//set redis
	var key = constant.REDIS_PREFIX_AUTH + tokenString
	json, _ := json.Marshal(user)
	err = redis.SetEx(key, string(json), expireTime.Unix())
	return tokenString, err
}

func GetUserInfo(tokenString string) (*JwtUser, error) {
	if tokenString == "" {
		return nil, errors.New("请传入token")
	}
	// 将token字符串解析为JWT对象
	token, _ := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
		return jwtSecret, nil
	})
	if token == nil {
		return nil, errors.New("令牌无效")
	}
	uClaims := userStdClaims{}
	_, err := jwt.ParseWithClaims(tokenString, &uClaims, func(token *jwt.Token) (i interface{}, err error) {
		// 直接使用标准的Claim则可以直接使用Parse方法
		//token, err := jwt.Parse(tokenString, func(token *jwt.Token) (i interface{}, err error) {
		return jwtSecret, nil
	})
	if err != nil {
		return nil, err
	}
	s := []string{uClaims.Uuid}
	users, err := model.FindUserByUuid(s)
	if err != nil {
		return nil, err
	}
	if len(users) == 0 {
		return nil, errors.New("未查询到用户")
	}
	user := users[0]
	user.Password = ""
	u, err := BackJwtUser(user)
	if err != nil {
		return nil, err
	}
	return &u, nil
}
func ValidateToken() gin.HandlerFunc {
	return func(c *gin.Context) {
		var (
			app = app.Gin{C: c}
		)
		tokenString := c.Request.Header.Get("Authorization")
		if tokenString == "" {
			app.Response(http.StatusBadRequest, "请登陆", nil)
			c.Abort()
			return
		}
		token, _ := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
			return jwtSecret, nil
		})
		if token == nil {
			app.Response(http.StatusBadRequest, "令牌无效", nil)
			c.Abort()
			return
		}

		uClaims := userStdClaims{}
		_, err := jwt.ParseWithClaims(tokenString, &uClaims, func(token *jwt.Token) (i interface{}, err error) {
			// 直接使用标准的Claim则可以直接使用Parse方法
			//token, err := jwt.Parse(tokenString, func(token *jwt.Token) (i interface{}, err error) {
			return jwtSecret, nil
		})
		if err != nil {
			var str string
			if v, ok := err.(*jwt.ValidationError); ok {
				if v.Errors&jwt.ValidationErrorMalformed != 0 { // 令牌不完整，就是说不是有效的jwt token 格式
					str = "令牌不完整"
				} else if v.Errors&jwt.ValidationErrorExpired != 0 { // 令牌过期
					str = "令牌过期"
				} else if v.Errors&jwt.ValidationErrorNotValidYet != 0 { // 令牌还未生效
					str = "令牌还未生效"
				} else {
					str = "无效"
				}
			}
			app.Response(http.StatusBadRequest, str, nil)
			c.Abort()
			return
		}
		s := []string{uClaims.Uuid}
		users, err := model.FindUserByUuid(s)
		if err != nil {
			app.Response(http.StatusBadRequest, err.Error(), nil)
			c.Abort()
			return
		}
		if len(users) == 0 {
			app.Response(http.StatusBadRequest, "未查询到用户", nil)
			c.Abort()
			return
		}
		user := users[0]
		u, err := BackJwtUser(user)
		if err != nil {
			app.Response(http.StatusBadRequest, err.Error(), nil)
			c.Abort()
			return
		}
		c.Set("user", u)
		c.Next()
	}
}

func BackJwtUser(user types.User) (JwtUser, error) {
	var (
		u JwtUser
		s = make([]types.UserShop, 0)
	)
	u.Account = user.Account
	u.NickName = user.NickName
	u.Phone = user.Phone
	u.Sex = user.Sex
	u.Uuid = user.Uuid
	u.Id = user.Id
	u.Auth = user.Auth

	// 是超级管理员 返回所有店铺
	if user.Auth == auth.Super_administrator {
		shops, err := model.FindShopByUUids()
		if err != nil {
			return u, err
		}
		s = shops

	} else { // 不是 就查询绑定的店铺
		if user.Shops == "" {
			return u, errors.New("未绑定店铺，请联系管理员")
		} else {
			uuids := strings.Split(user.Shops, ",")
			shops, err := model.FindShopByUUids(uuids...)
			if err != nil {
				return u, err
			} else {
				s = shops
			}
		}
	}
	u.Shops = s
	return u, nil
}
